package com.terrapages.wmsc4j.utils.seed;

import java.math.BigInteger;

import org.apache.log4j.Logger;

import com.terrapages.wmsc4j.layer.AbstractLiveLayer;
import com.terrapages.wmsc4j.layer.WMSMetaLayer;
import com.terrapages.wmsc4j.layer.tile.Tile;

/**
 * Class that enables one to seed a layer with tile images.
 * 
 * @author mvivian
 */
public class Seeder{
	private AbstractLiveLayer layer;
	private long logInterval = MINUTE;
	
	/**
	 * pass to setLogInterval() and will display seed info logs every second
	 * You can perform arithmatic on this value. eg '5 * SECOND' for  5 seconds
	 */
	public static long SECOND = 1000;
	/**
	 * pass to setLogInterval() and will display seed info logs every minute
	 */
	public static long MINUTE = 60000;
	/**
	 * pass to setLogInterval() and will display seed info logs every hour
	 */
	public static long HOUR = 3600000;
	
	private final static BigInteger HUNDRED = BigInteger.valueOf(100);
	
	private static Logger log = Logger.getLogger(Seeder.class);
	
	/**
	 * Creates a seeder that will seed all the cache images for the given layer using the WMSService given.
	 * By default info logs will be generated every minute. Use the setLogInterval() if you would like logs more or less often.
	 * @param layer - The layer to seed
	 * @param seed - The WMSService to get the seed images from
	 */
	public Seeder(AbstractLiveLayer layer) {
		this.layer = layer;
	}

	/**
	 * Begins seeding the layer given in the constructor using the WMS service passed in by the constructor.
	 */
	public void start()
	{
		
		final BigInteger layerSize = layer.size();
		BigInteger tileNum = BigInteger.ZERO;

		long lastOutput = System.currentTimeMillis();
		log.info("Started seeding. " + layerSize + " tiles to seed.");
		
		//how many tiles are cached at a time due to meta-tiling
		BigInteger numOfTiles = BigInteger.ONE;
		//Which Iterable to use
		Iterable<? extends Tile> iter = layer;
		
		if (layer instanceof WMSMetaLayer) {
			WMSMetaLayer metaLayer = (WMSMetaLayer) layer;
			numOfTiles = BigInteger.valueOf((long)Math.pow(metaLayer.getMultiplicity(),2));
			iter = metaLayer.getMetaIterable();
		}
		
		//start the seeding
		for (Tile tile: iter)
		{
			layer.getTile(tile);
			
			//every so often output progres;
			tileNum = tileNum.add(numOfTiles); //keep count of tiles
			
			if(System.currentTimeMillis() - lastOutput > logInterval){
				log.info(tileNum.multiply(HUNDRED).divide(layerSize)+ "% Complete. (" + tileNum + " of " + layerSize + ")");
				lastOutput = System.currentTimeMillis();
			}
		}
		log.info("Finished seeding. " + tileNum + " tiles seeded.");
	}

	/**
	 * @return the number of milliseconds between log outputs when seeding
	 */
	public final long getLogInterval() {
		return logInterval;
	}

	/**
	 * Sets the interval between log outputs when seeding.
	 * Note, setting this to 0 will output a line for every tile cached.
	 * @param logInterval the interval in milliseconds
	 */
	public final void setLogInterval(long logInterval) {
		this.logInterval = logInterval;
	}
}
